package jjsan.callback.phone;

import java.lang.reflect.Method;

import jjsan.callback.BaseActivity;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
//import android.widget.Toast;

import com.android.internal.telephony.ITelephony;

public class CallAnswerActivity extends BaseActivity {
	/**
	 * whether or not to use the AIDL technique or the HEADSET_HOOK/package
	 * restart techniques
	 */
	private static final boolean USE_ITELEPHONY = true;
	private static boolean CALLBACK = false;
	//private static int _PAUSE_TIME = 0;
	private static String phonenumber;

	public static final String PREFS_NAME = "MyPrefsFile";

	/**
	 * internal phone state broadcast receiver
	 */
	protected BroadcastReceiver r;

	/**
	 * TelephonyManager instance used by this activity
	 */
	private TelephonyManager tm;

	/**
	 * AIDL access to the telephony service process
	 */
	private ITelephony telephonyService;

	// ------------------------------------------------------------------------
	// primary life cycle call backs
	// ------------------------------------------------------------------------

	/**
	 * main() :)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		
		//get callback settings
		SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
		boolean _CALLBACK = settings.getBoolean("callback_enabled", true);
		
		if (_CALLBACK) { //is CALLBACK ENABLED?
		
		debugLog("onCreate called");
		setContentView(R.layout.callanswerscreen);

		// grab an instance of telephony manager
		tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

		// connect to the underlying Android telephony system
		if (USE_ITELEPHONY)
			connectToTelephonyService();

		// turn our idle phone state receiver on
		registerReciever();
		
		
		// touch screen reject/ignore call button
		Button rejectCall = (Button) findViewById(R.id.btnReject);
		if (getSharedPreferences(Hc.PREFSNAME, 0).getBoolean(
				Hc.PREF_ALLOW_REJECT_KEY, true))
			rejectCall.setOnClickListener(new RejectCallOnClickListener());
		else
			rejectCall.setVisibility(View.GONE);

		// touch screen answer button
		Button answerButton = (Button) findViewById(R.id.btnAccept);
		if (getSharedPreferences(Hc.PREFSNAME, 0).getBoolean(
				Hc.PREF_ALLOW_ACCEPT_KEY, true))
			answerButton.setOnClickListener(new AnswerCallOnClickListener());
		else
			answerButton.setVisibility(View.GONE);

		// touch screen callback button
		Button btnCallBack = (Button) findViewById(R.id.btnCallBack);
		if (getSharedPreferences(Hc.PREFSNAME, 0).getBoolean(
				Hc.PREF_ALLOW_CALLBACK_KEY, true))
			btnCallBack.setOnClickListener(new CallBackOnClickListener());
		else
			btnCallBack.setVisibility(View.GONE);

		// set colours of buttons
		rejectCall.getBackground().setColorFilter(0xFFFF0101,
				PorterDuff.Mode.MULTIPLY);
		answerButton.getBackground().setColorFilter(0xFF00FF00,
				PorterDuff.Mode.MULTIPLY);
		btnCallBack.getBackground().setColorFilter(0xFF0000FF,
				PorterDuff.Mode.MULTIPLY);
	} //if we dont have callback enabled
	}

	/**
	 * (re)register phone state receiver on resume, exit if the phone is idle
	 */
	@Override
	protected void onResume() {
		super.onResume();

		registerReciever();

		if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
			debugLog("phone is idle, stopping.");
			exitCleanly();
		}
	}

	/**
	 * unregister phone state receiver, schedule restart if not exiting at the
	 * users request
	 */
	@Override
	protected void onPause() {
		super.onPause();

		unHookReceiver();

		if (!isFinishing()) {
			debugLog("system forced pause occured, scheduling delayed restart");
			Intent i = new Intent(getApplicationContext(),
					CallAnswerIntentService.class);

			startService(i);
		}
	}

	// ------------------------------------------------------------------------
	// Input event handler call backs
	// ------------------------------------------------------------------------

	/**
	 * Camera button press event handler that will answer a call
	 */
	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {

		switch (event.getKeyCode()) {
		case KeyEvent.KEYCODE_FOCUS:
			return true;
		case KeyEvent.KEYCODE_CAMERA:
			answerCall();
			return true;
		case KeyEvent.KEYCODE_DPAD_CENTER:
			answerCall();
			return true;
		}
		return super.dispatchKeyEvent(event);
	}

	/**
	 * CallBack button long click listener will hangup call and make call to
	 * number.
	 */
	private class CallBackOnClickListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			debugLog("touch screen callback onClick event");
			
			CALLBACK = true;
			
			ignoreCall();
			// return true;
		}
	}

	/**
	 * Reject button long click listener will reject the incoming call.
	 */
	private class RejectCallOnClickListener implements OnClickListener {
		@Override
		public void onClick(View v) {

			//Toast.makeText(getApplicationContext(), getString(R.string.btnReject_toast),Toast.LENGTH_SHORT).show();
			debugLog("touch screen ignore call button onClick event");
			ignoreCall();
			exitCleanly();
			// return true;
		}
	}

	/**
	 * Answer button long click listener will answer the incoming call.
	 */
	private class AnswerCallOnClickListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			//Toast.makeText(getApplicationContext(), getString(R.string.btnAccept_toast), Toast.LENGTH_SHORT).show();
			debugLog("touch screen answer button onClick event");
			answerCall();
			// return true;
		}
	}

	// ------------------------------------------------------------------------
	// broadcast receivers
	// ------------------------------------------------------------------------

	/**
	 * register phone state receiver
	 */
	private void registerReciever() {
		if (r != null)
			return;

		r = new BroadcastReceiver() {
			@Override
			public void onReceive(Context c, Intent i) {
				String phone_state = i
						.getStringExtra(TelephonyManager.EXTRA_STATE);
				phonenumber = i
						.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
				if (!phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
					debugLog("received " + phone_state
							+ ", time to go bye bye, thanks for playing!");
					exitCleanly();
				}
			}
		};

		registerReceiver(r, new IntentFilter(
				"android.intent.action.PHONE_STATE"));
	}

	/**
	 * unregister phone state receiver
	 */
	private void unHookReceiver() {
		if (r != null) {
			unregisterReceiver(r);
			r = null;
		}
	}

	// ------------------------------------------------------------------------
	// application methods
	// ------------------------------------------------------------------------

	/**
	 * get an instance of ITelephony to talk handle calls with
	 */
	private void connectToTelephonyService() {
		try {
			// "cheat" with Java reflection to gain access to TelephonyManager's
			// ITelephony getter
			@SuppressWarnings("rawtypes")
			Class c = Class.forName(tm.getClass().getName());
			Method m = c.getDeclaredMethod("getITelephony");
			m.setAccessible(true);
			telephonyService = (ITelephony) m.invoke(tm);

		} catch (Exception e) {
			e.printStackTrace();
			debugLog("FATAL ERROR: could not connect to telephony subsystem");
			debugLog("Exception object: " + e);
			finish();
		}
	}

	//
	// answer call
	//

	/**
	 * answer incoming calls
	 */
	private void answerCall() {
		if (USE_ITELEPHONY)
			answerCallAidl();
		else
			answerCallHeadsetHook();

		exitCleanly();
	}

	/**
	 * ACTION_MEDIA_BUTTON broadcast technique for answering the phone
	 */
	private void answerCallHeadsetHook() {
		KeyEvent headsetHook = new KeyEvent(KeyEvent.ACTION_DOWN,
				KeyEvent.KEYCODE_HEADSETHOOK);
		Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
		mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, headsetHook);
		sendOrderedBroadcast(mediaButtonIntent, null);
	}

	/**
	 * AIDL/ITelephony technique for answering the phone
	 */
	private void answerCallAidl() {
		try {
			telephonyService.silenceRinger();
			telephonyService.answerRingingCall();
		} catch (RemoteException e) {
			e.printStackTrace();
			errorLog("FATAL ERROR: call to service method answerRiningCall failed.");
			errorLog("Exception object: " + e);
		}
	}

	//
	// ignore call
	//

	/**
	 * ignore incoming calls
	 */
	private void ignoreCall() {
		if (USE_ITELEPHONY)
			ignoreCallAidl();
		else
			ignoreCallPackageRestart();

	}

	/**
	 * package restart technique for ignoring calls
	 */
	private void ignoreCallPackageRestart() {
		ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
		am.restartPackage("com.android.providers.telephony");
		am.restartPackage("com.android.phone");
	}

	/**
	 * AIDL/ITelephony technique for ignoring calls
	 */
	private void ignoreCallAidl() {
		try {
			telephonyService.silenceRinger();
			telephonyService.endCall();
		} catch (RemoteException e) {
			e.printStackTrace();
			errorLog("FATAL ERROR: call to service method endCall failed.");
			errorLog("Exception object: " + e);
		}
	}

	/**
	 * cleanup and exit routine
	 */
	private void exitCleanly() {

		unHookReceiver();
		moveTaskToBack(true);
		finish();

		if (CALLBACK) {

			// get pause time
			SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
			int tmp_pause = settings.getInt("pause_time", 0);

			//Toast.makeText(getApplicationContext(), getString(R.string.redial_toast), Toast.LENGTH_SHORT).show();

			// pause
			try {
				Thread.sleep(tmp_pause * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// ///Toast.makeText(getApplicationContext(), getString(PAUSETIME),
			// Toast.LENGTH_LONG).show();

			// make a call
			Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"
					+ phonenumber));
			startActivity(callIntent);
		}

	}

	// ------------------------------------------------------------------------
	// debugging
	// ------------------------------------------------------------------------

	@Override
	protected void onStart() {
		super.onStart();
		debugLog("onStart");
	}

	@Override
	protected void onStop() {
		super.onStop();
		debugLog("stopped, finishing? " + isFinishing());
	}

	@Override
	protected void onDestroy() {
		super.onStop();
		debugLog("destroyed");
	}

	private void debugLog(String s) {
		super.debugLog("CallAnswerActivity", s);
	}

	private void errorLog(String s) {
		super.errorLog("CallAnswerActivity", s);
	}

}

/*
 * 
 * Notes
 * 
 * I. KEYCODE_HEADSETHOOK The "magic" goes here.
 * 
 * Programmatically mimic the press of the button on a head set used to answer
 * an incoming call. The recipe to do this is as follows:
 * 
 * intent - ACTION_MEDIA_BUTTON action - ACTION_DOWN code - KEYCODE_HEADSETHOOK
 * 
 * Broadcasting that intent answers the phone =)
 * 
 * However, if there are any other apps that are listening for
 * ACTION_MEDIA_BUTTION intents and consuming them they won't get to the Phone
 * app.
 * 
 * 
 * II. case KeyEvent.KEYCODE_FOCUS: this event occurs when you press down
 * lightly on the camera button e.g. auto focus. The event happens a lot even
 * when you press down hard (as the button is on its way down to the
 * "hard press"). returning true to consume the event and prevent further
 * processing of it by other apps
 */